#!/bin/bash 

CHANNEL_ID=$1
CA_FILE=/opt/config/crypto-config/ordererOrganizations/orderer.sample.com/tlsca/tlsca.orderer.sample.com-cert.pem
setEnv() {
    export CORE_PEER_LOCALMSPID=$2 
    export CORE_PEER_ADDRESS=peer0.$1.sample.com:7051 
    export CORE_PEER_MSPCONFIGPATH=/opt/config/crypto-config/peerOrganizations/$1.sample.com/users/Admin@$1.sample.com/msp
    export CORE_PEER_TLS_ROOTCERT_FILE=/opt/config/crypto-config/peerOrganizations/$1.sample.com/tlsca/tlsca.$1.sample.com-cert.pem
}

setOrdererEnv() {
    export CORE_PEER_LOCALMSPID=OrdererMSP 
    export CORE_PEER_ADDRESS=peer0.org1.sample.com:7051 
    export CORE_PEER_MSPCONFIGPATH=/opt/config/crypto-config/ordererOrganizations/orderer.sample.com/users/Admin@orderer.sample.com/msp
    export CORE_PEER_TLS_ROOTCERT_FILE=/opt/config/crypto-config/ordererOrganizations/orderer.sample.com/tlsca/tlsca.orderer.sample.com-cert.pem
}

if test -z $CHANNEL_ID; then 
    echo "channel id is required."
    exit 1
fi 

fetchChannelConfig() {
    peer channel fetch config $CHANNEL_ID.block -o orderer0.orderer.sample.com:7050 -c $CHANNEL_ID --tls --cafile $CA_FILE
    if [[ $? -ne 0 ]]; then 
        echo "fetch config fail."
        exit 1
    fi 

    echo "2. proto decode to json"
    configtxlator proto_decode --input $CHANNEL_ID.block --type common.Block | jq .data.data[0].payload.data.config > ${CHANNEL_ID}_config.json
    if [[ $? -ne 0 ]]; then 
        echo "[line: $LINENO] proto_decode config fail."
        exit 1
    fi
}

updateOrdererCapabilities() {
    echo "1. fetch system channel config"
    setEnv "org1" "Org1MSP"
    peer channel fetch config $CHANNEL_ID.block -o orderer0.orderer.sample.com:7050 -c $CHANNEL_ID --tls --cafile $CA_FILE
    if [[ $? -ne 0 ]]; then 
        echo "fetch config fail."
        exit 1
    fi 

    echo "2. proto decode to json"
    configtxlator proto_decode --input $CHANNEL_ID.block --type common.Block | jq .data.data[0].payload.data.config > ${CHANNEL_ID}_config.json
    if [[ $? -ne 0 ]]; then 
        echo "[line: $LINENO] proto_decode config fail."
        exit 1
    fi

    echo "3. update config"
    jq -s '.[0] * {"channel_group":{"groups":{"Orderer": {"values": {"Capabilities": .[1].orderer}}}}}' ${CHANNEL_ID}_config.json capabilities.json > ${CHANNEL_ID}_newconfig.json
    echo "4. compute update different package"
    configtxlator proto_encode --input ${CHANNEL_ID}_config.json --type common.Config --output ${CHANNEL_ID}_orig_config.pb
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] proto_encode fail"
        exit 1
    fi 
    configtxlator proto_encode --input ${CHANNEL_ID}_newconfig.json --type common.Config --output ${CHANNEL_ID}_update_config.pb 
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] proto_encode fail"
        exit 1
    fi

    configtxlator compute_update --channel_id $CHANNEL_ID --original ${CHANNEL_ID}_orig_config.pb --updated ${CHANNEL_ID}_update_config.pb --output ${CHANNEL_ID}_diff_config.pb
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] compute_update fail"
        exit 1
    fi

    echo "5. create update envelope"
    configtxlator proto_decode --input ${CHANNEL_ID}_diff_config.pb --type common.ConfigUpdate --output ${CHANNEL_ID}_diff_config.json 

    echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL_ID'", "type":2}},"data":{"config_update":'$(cat ${CHANNEL_ID}_diff_config.json)'}}}' | jq . > ${CHANNEL_ID}_update_in_envelope.json

    configtxlator proto_encode --input ${CHANNEL_ID}_update_in_envelope.json --type common.Envelope --output ${CHANNEL_ID}_update_in_envelope.pb 
    
    setOrdererEnv
    peer channel signconfigtx -f ${CHANNEL_ID}_update_in_envelope.pb

    setEnv "org1" "Org1MSP"
    sleep 0.5
    peer channel update -f ${CHANNEL_ID}_update_in_envelope.pb -c $CHANNEL_ID -o orderer0.orderer.sample.com:7050 --tls --cafile $CA_FILE
}

updateChannelCapabilities() {
    echo "1. fetch system channel config"
    setEnv "org1" "Org1MSP"
    peer channel fetch config $CHANNEL_ID.block -o orderer0.orderer.sample.com:7050 -c $CHANNEL_ID --tls --cafile $CA_FILE
    if [[ $? -ne 0 ]]; then 
        echo "fetch config fail."
        exit 1
    fi 

    echo "2. proto decode to json"
    configtxlator proto_decode --input $CHANNEL_ID.block --type common.Block | jq .data.data[0].payload.data.config > ${CHANNEL_ID}_config.json
    if [[ $? -ne 0 ]]; then 
        echo "[line: $LINENO] proto_decode config fail."
        exit 1
    fi

    echo "3. update channel config"
    jq -s '.[0] * {"channel_group":{"values":{"Capabilities": .[1].channel}}}' ${CHANNEL_ID}_config.json capabilities.json > ${CHANNEL_ID}_newconfig.json

    echo "4. compute update different package"
    configtxlator proto_encode --input ${CHANNEL_ID}_config.json --type common.Config --output ${CHANNEL_ID}_orig_config.pb
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] proto_encode fail"
        exit 1
    fi 
    configtxlator proto_encode --input ${CHANNEL_ID}_newconfig.json --type common.Config --output ${CHANNEL_ID}_update_config.pb 
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] proto_encode fail"
        exit 1
    fi

    configtxlator compute_update --channel_id $CHANNEL_ID --original ${CHANNEL_ID}_orig_config.pb --updated ${CHANNEL_ID}_update_config.pb --output ${CHANNEL_ID}_diff_config.pb
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] compute_update fail"
        exit 1
    fi

    echo "5. create update envelope"
    configtxlator proto_decode --input ${CHANNEL_ID}_diff_config.pb --type common.ConfigUpdate --output ${CHANNEL_ID}_diff_config.json 

    echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL_ID'", "type":2}},"data":{"config_update":'$(cat ${CHANNEL_ID}_diff_config.json)'}}}' | jq . > ${CHANNEL_ID}_update_in_envelope.json

    configtxlator proto_encode --input ${CHANNEL_ID}_update_in_envelope.json --type common.Envelope --output ${CHANNEL_ID}_update_in_envelope.pb 
    
    setOrdererEnv
    peer channel signconfigtx -f ${CHANNEL_ID}_update_in_envelope.pb
    setEnv "org1" "Org1MSP"
    peer channel signconfigtx -f ${CHANNEL_ID}_update_in_envelope.pb
    setEnv "org2" "Org2MSP"
    peer channel signconfigtx -f ${CHANNEL_ID}_update_in_envelope.pb

    setEnv "org1" "Org1MSP"
    sleep 0.5
    peer channel update -f ${CHANNEL_ID}_update_in_envelope.pb -c $CHANNEL_ID -o orderer0.orderer.sample.com:7050 --tls --cafile $CA_FILE
}

updateApplicationCapabilities() {
    echo "1. fetch system channel config"
    setEnv "org1" "Org1MSP"
    peer channel fetch config $CHANNEL_ID.block -o orderer0.orderer.sample.com:7050 -c $CHANNEL_ID --tls --cafile $CA_FILE
    if [[ $? -ne 0 ]]; then 
        echo "fetch config fail."
        exit 1
    fi 

    echo "2. proto decode to json"
    configtxlator proto_decode --input $CHANNEL_ID.block --type common.Block | jq .data.data[0].payload.data.config > ${CHANNEL_ID}_config.json
    if [[ $? -ne 0 ]]; then 
        echo "[line: $LINENO] proto_decode config fail."
        exit 1
    fi

    echo "3. update config"
    jq -s '.[0] * {"channel_group":{"groups":{"Application": {"values": {"Capabilities": .[1].application}}}}}' ${CHANNEL_ID}_config.json capabilities.json > ${CHANNEL_ID}_newconfig.json

    echo "4. compute update different package"
    configtxlator proto_encode --input ${CHANNEL_ID}_config.json --type common.Config --output ${CHANNEL_ID}_orig_config.pb
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] proto_encode fail"
        exit 1
    fi 
    configtxlator proto_encode --input ${CHANNEL_ID}_newconfig.json --type common.Config --output ${CHANNEL_ID}_update_config.pb 
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] proto_encode fail"
        exit 1
    fi

    configtxlator compute_update --channel_id $CHANNEL_ID --original ${CHANNEL_ID}_orig_config.pb --updated ${CHANNEL_ID}_update_config.pb --output ${CHANNEL_ID}_diff_config.pb
    if [[ $? -ne 0 ]]; then 
        echo "[line:$LINENO] compute_update fail"
        exit 1
    fi

    echo "5. create update envelope"
    configtxlator proto_decode --input ${CHANNEL_ID}_diff_config.pb --type common.ConfigUpdate --output ${CHANNEL_ID}_diff_config.json 

    echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL_ID'", "type":2}},"data":{"config_update":'$(cat ${CHANNEL_ID}_diff_config.json)'}}}' | jq . > ${CHANNEL_ID}_update_in_envelope.json

    configtxlator proto_encode --input ${CHANNEL_ID}_update_in_envelope.json --type common.Envelope --output ${CHANNEL_ID}_update_in_envelope.pb 
    
    setEnv "org1" "Org1MSP"
    peer channel signconfigtx -f ${CHANNEL_ID}_update_in_envelope.pb
    setEnv "org2" "Org2MSP"
    peer channel signconfigtx -f ${CHANNEL_ID}_update_in_envelope.pb

    setEnv "org1" "Org1MSP"
    sleep 0.5
    peer channel update -f ${CHANNEL_ID}_update_in_envelope.pb -c $CHANNEL_ID -o orderer0.orderer.sample.com:7050 --tls --cafile $CA_FILE
    if [[ $? -ne 0 ]]; then 
        echo "update fail."
        exit 1
    fi 
}

echo "*** Update Orderer Capabilities ***"
updateOrdererCapabilities 
rm -f $CHANNEL_ID*

echo "*** Update Channel Capabilities ***"
updateChannelCapabilities 
rm -f $CHANNEL_ID*

echo "*** Update Application Capabilities ***"
updateApplicationCapabilities